﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using E4RPManager.DataSets;
using E4RPTools;

namespace E4RPManager
{
    public class Database
    {
        #region Partner

        private static long GetPartnerId(SqlDataAccess sqlDataAccess, SqlTransaction sqlTransaction)
        {
            const string query =
                @"  select  max(Id)
                    from    Parceiro";
            return sqlDataAccess.ExecuteScalar(sqlTransaction, -1, query);
        }

        private static void InsertPartner(SqlTransaction sqlTransaction, ParceiroDataSet.ParceiroRow partner)
        {
            const string query =
                @"  insert 
                    into    Parceiro(Nome, Morada, Cidade, CodigoPostal, Contribuinte, Telefone, EMail, Observacoes, EnderecoWeb, Fax) 
                    values  (@Nome, @Morada, @Cidade, @CodigoPostal, @Contribuinte, @Telefone, @EMail, @Observacoes, @EnderecoWeb, @Fax)";
            var sqlParameters = new List<SqlParameter>
                                    {
                                        new SqlParameter("Nome", partner.Nome),
                                        new SqlParameter("Morada", partner.IsMoradaNull() ? Convert.DBNull : partner.Morada),
                                        new SqlParameter("Cidade", partner.IsCidadeNull() ? Convert.DBNull : partner.Cidade),
                                        new SqlParameter("CodigoPostal", partner.IsCodigoPostalNull() ? Convert.DBNull : partner.CodigoPostal),
                                        new SqlParameter("Contribuinte", partner.IsContribuinteNull() ? Convert.DBNull : partner.Contribuinte),
                                        new SqlParameter("Telefone", partner.IsTelefoneNull() ? Convert.DBNull : partner.Telefone),
                                        new SqlParameter("EMail", partner.IsEMailNull() ? Convert.DBNull : partner.EMail),
                                        new SqlParameter("Observacoes", partner.IsObservacoesNull() ? Convert.DBNull : partner.Observacoes),
                                        new SqlParameter("EnderecoWeb", partner.IsEnderecoWebNull() ? Convert.DBNull : partner.EnderecoWeb),
                                        new SqlParameter("Fax", partner.IsFaxNull() ? Convert.DBNull : partner.Fax)                                        
                                    };
            using (var sqlDataAccess = new SqlDataAccess())
            {
                sqlDataAccess.ExecuteNonQuery(sqlTransaction, query, sqlParameters.ToArray());
                partner.Id = GetPartnerId(sqlDataAccess, sqlTransaction);
            }
        }

        private static void UpdatePartner(SqlTransaction sqlTransaction, ParceiroDataSet.ParceiroRow partner)
        {
            const string query =
                @"  update  Parceiro
                    set     Nome = @Nome, 
                            Morada = @Morada, 
                            Cidade = @Cidade, 
                            CodigoPostal = @CodigoPostal, 
                            Contribuinte = @Contribuinte, 
                            Telefone = @Telefone, 
                            EMail = @EMail, 
                            Observacoes = @Observacoes, 
                            EnderecoWeb = @EnderecoWeb, 
                            Fax = @Fax
                    where   Id = @Id";
            var sqlParameters = new List<SqlParameter>
                                    {
                                        new SqlParameter("Id", partner.Id),
                                        new SqlParameter("Nome", partner.Nome),
                                        new SqlParameter("Morada", partner.IsMoradaNull() ? Convert.DBNull : partner.Morada),
                                        new SqlParameter("Cidade", partner.IsCidadeNull() ? Convert.DBNull : partner.Cidade),
                                        new SqlParameter("CodigoPostal", partner.IsCodigoPostalNull() ? Convert.DBNull : partner.CodigoPostal),
                                        new SqlParameter("Contribuinte", partner.IsContribuinteNull() ? Convert.DBNull : partner.Contribuinte),
                                        new SqlParameter("Telefone", partner.IsTelefoneNull() ? Convert.DBNull : partner.Telefone),
                                        new SqlParameter("EMail", partner.IsEMailNull() ? Convert.DBNull : partner.EMail),
                                        new SqlParameter("Observacoes", partner.IsObservacoesNull() ? Convert.DBNull : partner.Observacoes),
                                        new SqlParameter("EnderecoWeb", partner.IsEnderecoWebNull() ? Convert.DBNull : partner.EnderecoWeb),
                                        new SqlParameter("Fax", partner.IsFaxNull() ? Convert.DBNull : partner.Fax)
                                    };
            using (var sqlDataAccess = new SqlDataAccess())
                sqlDataAccess.ExecuteNonQuery(sqlTransaction, query, sqlParameters.ToArray());
        }

        
        public static ParceiroDataSet GetPartners(SqlTransaction sqlTransaction)
        {
            var dataSet = new ParceiroDataSet();
            const string query =
                @"  select	Id, Nome, Morada, Cidade, CodigoPostal, Contribuinte, Telefone, EMail, Observacoes, EnderecoWeb, Fax
		            from	Parceiro
                    order by Nome";
            using (var dataAccess = new SqlDataAccess())
                dataAccess.Fill(sqlTransaction, dataSet.Parceiro, query);
            return dataSet;
        }

        public static ParceiroDataSet GetPartner(SqlTransaction sqlTransaction, long id)
        {
            var dataSet = new ParceiroDataSet();
            const string messageQuery =
                @"  select	Id, Nome, Morada, Cidade, CodigoPostal, Contribuinte, Telefone, EMail, Observacoes, EnderecoWeb, Fax
		            from	Parceiro
                    where   Id = @Id";
            using (var dataAccess = new SqlDataAccess())
                dataAccess.Fill(sqlTransaction, dataSet.Parceiro, messageQuery, new SqlParameter("Id", id));
            return dataSet;
        }

        public static void SavePartner(SqlTransaction sqlTransaction, ParceiroDataSet.ParceiroRow partner)
        {
            if (partner.RowState == DataRowState.Added)
                InsertPartner(sqlTransaction, partner);
            else
                UpdatePartner(sqlTransaction, partner);
        }

        #endregion

        #region Client

        private static long GetClientId(SqlDataAccess sqlDataAccess, SqlTransaction sqlTransaction)
        {
            const string query =
                @"  select  max(Id)
                    from    Cliente";
            return sqlDataAccess.ExecuteScalar(sqlTransaction, -1, query);
        }

        private static void InsertClient(SqlTransaction sqlTransaction, ClienteDataSet.ClienteRow client)
        {
            const string query =
                @"  insert 
                    into    Cliente(Nome, Morada, Cidade, CodigoPostal, Contribuinte, Telefone, EMail, Observacoes, EnderecoWeb, Fax) 
                    values  (@Nome, @Morada, @Cidade, @CodigoPostal, @Contribuinte, @Telefone, @EMail, @Observacoes, @EnderecoWeb, @Fax)";
            var sqlParameters = new List<SqlParameter>
                                    {
                                        new SqlParameter("Nome", client.Nome),
                                        new SqlParameter("Morada", client.IsMoradaNull() ? Convert.DBNull : client.Morada),
                                        new SqlParameter("Cidade", client.IsCidadeNull() ? Convert.DBNull : client.Cidade),
                                        new SqlParameter("CodigoPostal", client.IsCodigoPostalNull() ? Convert.DBNull : client.CodigoPostal),
                                        new SqlParameter("Contribuinte", client.IsContribuinteNull() ? Convert.DBNull : client.Contribuinte),
                                        new SqlParameter("Telefone", client.IsTelefoneNull() ? Convert.DBNull : client.Telefone),
                                        new SqlParameter("EMail", client.IsEMailNull() ? Convert.DBNull : client.EMail),
                                        new SqlParameter("Observacoes", client.IsObservacoesNull() ? Convert.DBNull : client.Observacoes),
                                        new SqlParameter("EnderecoWeb", client.IsEnderecoWebNull() ? Convert.DBNull : client.EnderecoWeb),
                                        new SqlParameter("Fax", client.IsFaxNull() ? Convert.DBNull : client.Fax)                                        
                                    };
            using (var sqlDataAccess = new SqlDataAccess())
            {
                sqlDataAccess.ExecuteNonQuery(sqlTransaction, query, sqlParameters.ToArray());
                client.Id = GetClientId(sqlDataAccess, sqlTransaction);
            }
        }

        private static void UpdateClient(SqlTransaction sqlTransaction, ClienteDataSet.ClienteRow client)
        {
            const string query =
                @"  update  Cliente
                    set     Nome = @Nome, 
                            Morada = @Morada, 
                            Cidade = @Cidade, 
                            CodigoPostal = @CodigoPostal, 
                            Contribuinte = @Contribuinte, 
                            Telefone = @Telefone, 
                            EMail = @EMail, 
                            Observacoes = @Observacoes, 
                            EnderecoWeb = @EnderecoWeb, 
                            Fax = @Fax
                    where   Id = @Id";
            var sqlParameters = new List<SqlParameter>
                                    {
                                        new SqlParameter("Id", client.Id),
                                        new SqlParameter("Nome", client.Nome),
                                        new SqlParameter("Morada", client.IsMoradaNull() ? Convert.DBNull : client.Morada),
                                        new SqlParameter("Cidade", client.IsCidadeNull() ? Convert.DBNull : client.Cidade),
                                        new SqlParameter("CodigoPostal", client.IsCodigoPostalNull() ? Convert.DBNull : client.CodigoPostal),
                                        new SqlParameter("Contribuinte", client.IsContribuinteNull() ? Convert.DBNull : client.Contribuinte),
                                        new SqlParameter("Telefone", client.IsTelefoneNull() ? Convert.DBNull : client.Telefone),
                                        new SqlParameter("EMail", client.IsEMailNull() ? Convert.DBNull : client.EMail),
                                        new SqlParameter("Observacoes", client.IsObservacoesNull() ? Convert.DBNull : client.Observacoes),
                                        new SqlParameter("EnderecoWeb", client.IsEnderecoWebNull() ? Convert.DBNull : client.EnderecoWeb),
                                        new SqlParameter("Fax", client.IsFaxNull() ? Convert.DBNull : client.Fax)
                                    };
            using (var sqlDataAccess = new SqlDataAccess())
                sqlDataAccess.ExecuteNonQuery(sqlTransaction, query, sqlParameters.ToArray());
        }

        private static void DeleteClientProducts(SqlDataAccess sqlDataAccess, SqlTransaction sqlTransaction, long clientId)
        {
            const string query =
                @"  delete  ClienteProduto
                    where   IdCliente = @IdCliente";
            sqlDataAccess.ExecuteNonQuery(sqlTransaction, query, new SqlParameter("IdCliente", clientId));
        }

        private static void InsertClientProduct(SqlDataAccess sqlDataAccess, SqlTransaction sqlTransaction, ClienteDataSet.ClienteProdutoRow product)
        {
            if(product.IsRegistadoEmNull()) product.RegistadoEm = DateTime.Now;
            const string query =
                @"  insert 
                    into    ClienteProduto(IdCliente, IdProduto, Versao, Info, Validade, Licenca, Observacoes, IdParceiro, RegistadoEm, Factura, FacturadoEm) 
                    values  (@IdCliente, @IdProduto, @Versao, @Info, @Validade, @Licenca, @Observacoes, @IdParceiro, @RegistadoEm, @Factura, @FacturadoEm)";
            var sqlParameters = new List<SqlParameter>
                                    {
                                        new SqlParameter("IdCliente", product.IdCliente),
                                        new SqlParameter("IdProduto", product.IdProduto),
                                        new SqlParameter("Versao", product.IsVersaoNull() ? 1 : product.Versao),
                                        new SqlParameter("Info", product.Info),
                                        new SqlParameter("RegistadoEm", product.RegistadoEm),
                                        new SqlParameter("Validade", product.IsValidadeNull() ? Convert.DBNull : product.Validade),
                                        new SqlParameter("Licenca", product.IsLicencaNull() ?  Convert.DBNull : product.Licenca),
                                        new SqlParameter("Observacoes", product.IsObservacoesNull() ? Convert.DBNull : product.Observacoes),
                                        new SqlParameter("IdParceiro", product.IsIdParceiroNull() ? Convert.DBNull : product.IdParceiro),
                                        new SqlParameter("Factura", product.IsFacturadoEmNull() ? Convert.DBNull : product.Factura),
                                        new SqlParameter("FacturadoEm", product.IsFacturadoEmNull() ? Convert.DBNull : product.FacturadoEm)
                                    };
            sqlDataAccess.ExecuteNonQuery(sqlTransaction, query, sqlParameters.ToArray());
        }

        
        public static ClienteDataSet GetClients(SqlTransaction sqlTransaction)
        {
            var dataSet = new ClienteDataSet();
            const string clientQuery =
                @"  select	Id, Nome, Morada, Cidade, CodigoPostal, Contribuinte, Telefone, EMail, Observacoes, EnderecoWeb, Fax
		            from	Cliente
                    order by Nome";
            const string productQuery =
                @"  select	IdCliente, IdProduto, Versao, Info, Validade, Licenca, Observacoes, IdParceiro, RegistadoEm, Factura, FacturadoEm
		            from	ClienteProduto";
            using (var dataAccess = new SqlDataAccess())
            {
                dataAccess.Fill(sqlTransaction, dataSet.Cliente, clientQuery);
                dataAccess.Fill(sqlTransaction, dataSet.ClienteProduto, productQuery);
            }
            return dataSet;
        }

        public static ClienteDataSet GetClient(SqlTransaction sqlTransaction, long id)
        {
            var dataSet = new ClienteDataSet();
            const string messageQuery =
                @"  select	Id, Nome, Morada, Cidade, CodigoPostal, Contribuinte, Telefone, EMail, Observacoes, EnderecoWeb, Fax
		            from	Cliente
                    where   Id = @Id";
            const string contactsQuery =
                @"  select  IdCliente, IdProduto, Versao, Info, Validade, Licenca, Observacoes, IdParceiro, RegistadoEm, Factura, FacturadoEm
		            from    ClienteProduto
                    where   IdCliente = @Id";
            using (var dataAccess = new SqlDataAccess())
            {
                dataAccess.Fill(sqlTransaction, dataSet.Cliente, messageQuery, new SqlParameter("Id", id));
                dataAccess.Fill(sqlTransaction, dataSet.ClienteProduto, contactsQuery, new SqlParameter("Id", id));
            }
            return dataSet;
        }

        public static void SaveClient(SqlTransaction sqlTransaction, ClienteDataSet.ClienteRow client)
        {
            if (client.RowState == DataRowState.Added)
                InsertClient(sqlTransaction, client);
            else
                UpdateClient(sqlTransaction, client);
        }

        public static void UpdateClientProducts(SqlTransaction sqlTransaction, long clientId, ClienteDataSet.ClienteProdutoDataTable products)
        {
            using (var sqlDataAccess = new SqlDataAccess())
            {
                DeleteClientProducts(sqlDataAccess, sqlTransaction, clientId);
                products.AcceptChanges();
                foreach (ClienteDataSet.ClienteProdutoRow product in products)
                    product.SetAdded();
                foreach (ClienteDataSet.ClienteProdutoRow product in products)
                    InsertClientProduct(sqlDataAccess, sqlTransaction, product);
            }
        }

        #endregion
    }
}
